package com.yxx.service.Impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yxx.constant.ScheduleConstant;
import com.yxx.entity.Task;
import com.yxx.entityModel.vo.Result.PageResult;
import com.yxx.entityModel.vo.query.TaskQuery;
import com.yxx.entityModel.vo.request.StatusRequest;
import com.yxx.entityModel.vo.request.TaskRequest;
import com.yxx.entityModel.vo.request.TaskRunRequest;
import com.yxx.entityModel.vo.response.TaskBackResponse;
import com.yxx.enums.TaskStatusEnum;
import com.yxx.exception.ServiceException;
import com.yxx.mapper.TaskMapper;
import com.yxx.quartz.utils.CronUtils;
import com.yxx.quartz.utils.ScheduleUtils;
import com.yxx.service.TaskService;
import com.yxx.utils.BeanCopyUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @author yuxiangxun
 * @date 2025/2/16
 * @apiNote
 */
@Service
@Slf4j
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {
    @Resource
    private TaskMapper taskMapper;

    @Resource
    private Scheduler scheduler;

    /**
     * 查看定时任务列表
     * @param taskQuery
     * @return
     */
    @Override
    public PageResult<TaskBackResponse> taskBackList(TaskQuery taskQuery) {
        // 查询定时任务数量
        Long count = taskMapper.selectTaskCount(taskQuery);
        // 如果定时任务数量为0，则返回空结果
        if(count == 0){
            return new PageResult<>();
        }
        // 分页查询定时任务列表
        List<TaskBackResponse> taskBackResponseList =  taskMapper.selectTaskList(taskQuery);
        // 封装下次定时任务时间
        taskBackResponseList.forEach(taskBackResponse -> {
            // 是否有调度目标
            if(StringUtils.isNotEmpty(taskBackResponse.getCronExpression())){
                // 如果有调度目标，封装下次执行时间
                Date nextExecution = CronUtils.getNextExecution(taskBackResponse.getCronExpression());
                taskBackResponse.setNextValidTime(nextExecution);
            }else{
                // 没有调度目标，封装下次执行时间为 null 即可
                taskBackResponse.setNextValidTime(null);
            }
        });
        return new PageResult<>(taskBackResponseList, count);
    }

    /**
     * 添加定时任务
     * @param taskRequest
     */
    @Override
    public void addTask(TaskRequest taskRequest) {
        // 检查请求中的 cron执行表达式 是否格式正确  断言
        Assert.isTrue(CronUtils.isValid(taskRequest.getCronExpression()) , "cron表达式格式不正确");
        // 对象转换
        Task newTask = BeanCopyUtils.copyBean(taskRequest, Task.class);
        // 新增定时任务到数据库，返回新增的记录数
        int row = taskMapper.insert(newTask);
        // 新增定时任务
        if(row > 0){
            ScheduleUtils.createScheduleJob(scheduler,newTask);
        }
    }

    /**
     * 修改定时任务
     * @param taskRequest
     */
    @Override
    public void updateTask(TaskRequest taskRequest) {
        // 检查请求中的 cron执行表达式 是否格式正确  断言
        Assert.isTrue(CronUtils.isValid(taskRequest.getCronExpression()), "cron表达式格式不正确");
        // 要先查出原来未被修改的任务信息保存一份然后再更新任务信息 根据请求中的任务id查询对应已存在的任务对象
        Task existTask = taskMapper.selectById(taskRequest.getId());
        // 对象转换后，更新定时任务
        Task newTask = BeanCopyUtils.copyBean(taskRequest, Task.class);
        int row = taskMapper.updateById(newTask);
        if(row > 0){
            try{
                // 更新任务
                updateSchedulerJob(newTask,existTask.getTaskGroup());
            }catch (SchedulerException e){
                throw new ServiceException("更新定时任务");
            }
        }
    }



    /**
     * 更新任务
     * @param task
     * @param taskGroup
     */
    public void updateSchedulerJob(Task task, String taskGroup) throws SchedulerException{
        // 判断是否存在
        JobKey jobKey = ScheduleUtils.getJobKey(task.getId(), taskGroup);
        //  存在的话，就得防止创建时存在数据问题 先移除，然后在执行创建操作
        if(scheduler.checkExists(jobKey)){
            scheduler.deleteJob(jobKey);
        }
        ScheduleUtils.createScheduleJob(scheduler,task);
    }

    /**
     * 删除定时任务
     * @param taskIdList
     */
    @Override
    public void deleteTask(List<Integer> taskIdList) {
        // 删除数据库中定时任务的相关信息，先保存这一部分的定时任务对象，后续需要删除定时任务时需要
        List<Task> existTaskList = taskMapper.selectList(new LambdaQueryWrapper<Task>()
                        .select(Task::getId,Task::getTaskGroup)
                        .in(Task::getId, taskIdList));
        // 删除数据库中定时任务的相关信息
        int row = taskMapper.deleteBatchIds(taskIdList);
        // 删除定时任务
        if(row > 0){
            existTaskList.forEach(existTask -> {
                try{
                    scheduler.deleteJob(ScheduleUtils.getJobKey(existTask.getId(), existTask.getTaskGroup()));
                }catch(SchedulerException e){
                    throw new ServiceException("删除定时任务异常");
                }
            });
        }
    }

    /**
     * 修改定时任务状态
     * @param statusRequest
     */
    @Override
    public void updateTaskStatus(StatusRequest statusRequest) {
        // 根据请求中的任务id查询数据库中已经存在的任务对象
        Task task = taskMapper.selectById(statusRequest.getId());
        // 请求中的状态和查询出来的状态一致，直接返回
        if(task.getStatus().equals(statusRequest.getStatus())){
            return;
        }
        // 更新数据库中的定时任务状态
        Task newTask = Task.builder()
                .id(statusRequest.getId())
                .status(statusRequest.getStatus())
                .build();
        int row = taskMapper.updateById(newTask);
        // 获取定时任务状态、id、任务组
        Integer status = statusRequest.getStatus();
        Integer taskId = task.getId();
        String taskGroup = task.getTaskGroup();
        if(row > 0){
            // 更新定时任务
            try{
                if(TaskStatusEnum.RUNNING.getStatus().equals(status)){
                    scheduler.resumeJob(ScheduleUtils.getJobKey(taskId, taskGroup));
                }
                if(TaskStatusEnum.PAUSE.getStatus().equals(status)){
                    scheduler.pauseJob(ScheduleUtils.getJobKey(taskId, taskGroup));
                }
            }catch (SchedulerException e){
                throw new ServiceException("更新定时任务状态异常");
            }
        }

    }

    /**
     * 执行定时任务
     * @param taskRunRequest
     */
    @Override
    public void runTask(TaskRunRequest taskRunRequest) {
        // 获取请求中任务id
        Integer taskId = taskRunRequest.getId();
        // 获取请求中的任务组
        String taskGroup = taskRunRequest.getTaskGroup();
        // 根据此定时任务id 查询定时任务信息
        Task task = taskMapper.selectById(taskId);
        // 设置参数
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put(ScheduleConstant.TASK_PROPERTIES, task);
        try{
            scheduler.triggerJob(ScheduleUtils.getJobKey(taskId, taskGroup), jobDataMap);
        }catch (SchedulerException e){
            throw new ServiceException("执行定时任务异常");
        }
    }
}
